package constant

import (
	"sync"

	cmap "github.com/orcaman/concurrent-map/v2"
)

var (
	//-- 上报数据队列 --

	// 历史数据
	HisDataBucket []*CQueue
	// 历史system
	HisSystemBucket []*CQueue
	// 实时缓存
	SensorCache = cmap.New[map[string]interface{}]()
	// 待更新sn#key
	SensorSnKey = cmap.New[string]()
	// 待插入缓存
	SensorInsCache = cmap.New[map[string]interface{}]()

	// -- 设备队列 --

	// devSn - gateSn
	DevGateCache = cmap.New[string]()
	// gateSn - [devSn...]
	GateDevsCache = cmap.New[[]string]()
	// 设备在线缓存 devSn - lastLiveTime
	DevOnlineCache = cmap.New[string]()
	// 待更新sn末次
	StatusSnCache = cmap.New[string]()
	// gate-model
	GateModelCache = cmap.New[string]()
	// model-protocol
	ModelProtocolCache = cmap.New[string]()

	// -- 数据统计队列 --

	// sn-sum(count)
	DevDataCountCache = cmap.New[int]()
	// sn-sum(size)
	DevDataSizeCache = cmap.New[int]()
	// ruleId-sum(count)
	DevRuleCountCache = cmap.New[int]()
)

// ProductConfigCache 产品配置缓存
var ProductConfigCache sync.Map

type ProductConfig struct {
	LogoutTimeout int
}

func (p *ProductConfig) EnableLogoutTimeout() bool {
	if p.LogoutTimeout > 0 {
		return true
	}

	return false
}

// CQueue is a concurrent unbounded queue which uses two-Lock concurrent queue qlgorithm.
type CQueue struct {
	head  *cnode
	tail  *cnode
	hlock sync.Mutex
	tlock sync.Mutex
}
type cnode struct {
	value interface{}
	next  *cnode
}

// NewCQueue returns an empty CQueue.
func NewCQueue() *CQueue {
	n := &cnode{}
	return &CQueue{head: n, tail: n}
}

// Enqueue puts the given value v at the tail of the queue.
func (q *CQueue) Enqueue(v interface{}) {
	n := &cnode{value: v}
	q.tlock.Lock()
	q.tail.next = n // Link node at the end of the linked list
	q.tail = n      // Swing Tail to node
	q.tlock.Unlock()
}

// Dequeue removes and returns the value at the head of the queue.
// It returns nil if the queue is empty.
func (q *CQueue) Dequeue() interface{} {
	q.hlock.Lock()
	n := q.head
	newHead := n.next
	if newHead == nil {
		q.hlock.Unlock()
		return nil
	}
	v := newHead.value
	newHead.value = nil
	q.head = newHead
	q.hlock.Unlock()
	return v
}
